import time, os, base64, json
from functools import wraps
from flask import Flask, abort, request, jsonify, render_template, redirect, current_app, send_file
from flask_sqlalchemy import SQLAlchemy
from flask_cors import cross_origin
from pandas import DataFrame
from passlib.apps import custom_app_context as pwd_context
from itsdangerous import (TimedJSONWebSignatureSerializer
                          as Serializer, BadSignature, SignatureExpired)

# initialization
app = Flask(__name__)

app.config['SECRET_KEY'] = 'web front end'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///StuInfo.db'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True

# extensions
db = SQLAlchemy(app)


def support_jsonp(f):
    """Wraps JSONified output for JSONP"""

    @wraps(f)
    def decorated_function(*args, **kwargs):
        callback = request.args.get('callback', False)
        if callback:
            content = str(callback) + '(' + str(f(*args, **kwargs).data) + ')'
            return current_app.response_class(content, mimetype='application/javascript')
        else:
            return f(*args, **kwargs)

    return decorated_function


class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(32), index=True)
    password_hash = db.Column(db.String(64))
    imgpath = db.Column(db.String(64))
    imgstatus = db.Column(db.String(32))
    motto = db.Column(db.String(64))
    work1 = db.Column(db.String(32))
    work2 = db.Column(db.String(32))

    def hash_password(self, password):
        self.password_hash = pwd_context.encrypt(password)

    def verify_password(self, password):
        return pwd_context.verify(password, self.password_hash)

    def generate_auth_token(self, expiration=600):
        s = Serializer(app.config['SECRET_KEY'], expires_in=expiration)
        return s.dumps({'id': self.id})

    @staticmethod
    def verify_auth_token(token):
        s = Serializer(app.config['SECRET_KEY'])
        try:
            data = s.loads(token)
        except SignatureExpired:
            return None  # valid token, but expired
        except BadSignature:
            return None  # invalid token
        user = User.query.get(data['id'])
        return user


@app.route('/signup', methods=['POST', 'GET'])
def new_user():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        motto = request.form['motto']
    else:
        username = request.args.get('username')
        password = request.args.get('password')
        motto = request.args.get('motto')
    if username is None or password is None:
        abort(400)  # missing arguments
    if User.query.filter_by(username=username).first() is not None:
        abort(403)  # existing user
    user = User(username=username, motto=motto, work1='ok')
    user.hash_password(password)
    db.session.add(user)
    db.session.commit()
    return "Congratulation! You just signed up a new account,Here is your account infomation:\nusername: " + username + "\npassword: " + password + "\nmotto: " + motto


@app.route('/login', methods=['POST', 'GET'])
def logtheuserin():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
    else:
        username = request.args.get('username')
        password = request.args.get('password')
    user = User.query.filter_by(username=username).first()
    if user:
        if user.verify_password(password):
            token = user.generate_auth_token(600)
            user.work2 = 'ok'
            db.session.commit()
            return "hello! you successfully signed in your account,your token is " + token.decode('ascii')
        else:
            return "sorry,wrong password"
    else:
        return "sorry,wrong username"


@app.route('/uploadimage', methods=['POST'])
def upload_image():
    if request.method == 'POST':
        token = request.form['token']
    else:
        token = request.args.get('token')
    user = User.verify_auth_token(token)
    if user:
        img = base64.b64decode(request.form['image'])
        filename = 'static/image/' + user.username + '.jpg'
        file = open(filename, 'wb')
        file.write(img)
        file.close()
        user.imgpath = filename
        user.imgstatus = 'ok'
        db.session.commit()
        return "upload image success!"
    else:
        return "sorry,wrong username or password"


@app.route('/loginweb', methods=['POST'])
@cross_origin()
def loginweb():
    username = request.form['username']
    password = request.form['password']
    user = User.query.filter_by(username=username).first()
    if pwd_context.verify(password, pwd_context.encrypt(password)):
        s = Serializer(app.config['SECRET_KEY'], expires_in=600)
        token = s.dumps({'id': user.id})
        return jsonify({'token': token.decode('ascii'), 'imgpath': user.imgpath, 'motto': user.motto})
    else:
        abort(403)


@app.route('/mystatus', methods=['POST'])
@cross_origin()
def mystatus():
    token = request.form['token']
    user = User.verify_auth_token(token)
    if user:
        status = {'work1': user.work1, 'work2': user.work2, 'imgstatus': user.imgstatus}
        return jsonify(status)
    else:
        abort(403)


@app.route('/web')
def web():
    return render_template('html-dafault.html')


@app.route('/ticketpage')
def ticketpage():
    return render_template('demo.html')


@app.route('/ticketSlow')
@cross_origin()
def ticketSlow():
    with app.open_resource('ticketSlow.json') as f:
        data = json.load(f)
    return jsonify(data)


@app.route('/ticket')
@cross_origin()
def ticket():
    with app.open_resource('ticket.json') as f:
        data = json.load(f)
    return jsonify(data)


@app.route('/ticketNoCrossDomain', methods=['POST', 'GET'])
def ticketNoCrossDomain():
    return "Actually you can't receive this message from your browser if you use Ajax ^_^"


@app.route('/ticketJsonp', methods=['POST', 'GET'])
@support_jsonp
def ticketJsonp():
    a = json.load(app.open_resource('ticket.json'))
    return jsonify(a)


@app.route('/ticketFilter', methods=['POST', 'GET'])
@cross_origin()
def ticketFilter():
    if request.method == 'POST':
        fromCity = request.form['fromCity']
        toCity = request.form['toCity']
        setOutDate = request.form['setOutDate']
        returnDate = request.form['returnDate']
    else:
        fromCity = request.args.get('fromCity')
        toCity = request.args.get('toCity')
        setOutDate = request.args.get('setOutDate')
        returnDate = request.args.get('returnDate')

    with app.open_resource('ticket.json') as f:
        data = json.load(f)
        frame = DataFrame(data)
        if fromCity is not None:
            frame = frame[frame['fromCity'] == fromCity]
        if toCity is not None:
            frame = frame[frame['toCity'] == toCity]
        if setOutDate is not None:
            frame = frame[frame['setOutDate'] == setOutDate]
        if returnDate is not None:
            frame = frame[frame['returnDate'] == returnDate]
        return frame.to_json(orient='records')

@app.route('/city',methods=['POST','GET'])
@cross_origin()
def city():
    if request.method == 'POST':
        city = request.form['city']
        pinyin = request.form['pinyin']

    else:
        city = request.args.get('city')
        pinyin = request.args.get('pinyin')
    with app.open_resource('area.json') as f:
        data = json.load(f)
        frame = DataFrame(data)
        if city is not None:
            frame = frame[frame['city'] == city]
        if pinyin is not None:
            frame = frame[frame['pinyin'] == pinyin]

        return frame.to_json(orient='records')

if __name__ == '__main__':
    db.create_all()
    app.run(port=5001)
